// This file is a part of ChaosDB.
// Copyright (C) 2012 ChaoJianPeng
// email:chaojianpeng@gmail.com
//
// ChaosDB is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// ChaosDB is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

/*
 * common_respond.cpp
 *
 *  Created on: 2012-3-2
 *      Author: chao
 */

#include "respond.h"
#include "cmalloc.h"
#include <string.h>
#include <stdlib.h>

void addCmd(ByteArray* in, ByteArray* out);
void getCmd(ByteArray* in, ByteArray* out);
void setCmd(ByteArray* in, ByteArray* out);
void replaceCmd(ByteArray* in, ByteArray* out);
void removeCmd(ByteArray* in, ByteArray* out);
void addIndexCmd(ByteArray* in, ByteArray* out);
void delIndexCmd(ByteArray* in, ByteArray* out);
void getByIndexCmd(ByteArray* in, ByteArray* out);

/**
 * Result* 需要使用free释放
 */
Result* common(zmq_msg_t* request) {
	int size = zmq_msg_size(request);
	void* data = zmq_msg_data(request);

	ByteArray buffin, buffout;
	creatReadByteArray(&buffin, data, size);
	creatWriteByteArray(&buffout);

	int commonCode = 0;

	while (readInt(&commonCode, &buffin) != BYTE_ARRAY_EOF) {
		// 命令工厂
		switch (commonCode) {
		case ADD:
			addCmd(&buffin, &buffout);
			break;
		case GET:
			getCmd(&buffin, &buffout);
			break;
		case SET:
			setCmd(&buffin, &buffout);
			break;
		case REPLACE:
			replaceCmd(&buffin, &buffout);
			break;
		case REMOVE:
			removeCmd(&buffin, &buffout);
			break;
		case ADD_INDEX:
			addIndexCmd(&buffin, &buffout);
			break;
		case DEL_INDEX:
			delIndexCmd(&buffin, &buffout);
			break;
		case GET_BY_INDEX:
			getByIndexCmd(&buffin, &buffout);
			break;
		}
	}

	Result* rs = (Result*) malloc(sizeof(Result));
	rs->buff = buffout.data;
	rs->len = buffout.pos;
	return rs;
}

void addCmd(ByteArray* in, ByteArray* out) {

	int keylen, valuelen, res;
	char* key;
	void* value;
	// 添加
	// 数据包格式为:
	// keylen(int){不含\0} valuelen(int) key(char*){不含\0} value(void*)
	readInt(&keylen, in);
	readInt(&valuelen, in);

	// 长度错误
	if (keylen == 0 || valuelen == 0) {
		writeInt(&DB_ERROR, out);
		return;
	}

	key = (char*) cmalloc(keylen + 1);
	value = cmalloc(valuelen);
	readString(key, in, keylen);
	readBuff(value, in, valuelen);
	res = dbAdd(key, value, keylen, valuelen);

	// 内存不可再写，拒绝修改型命令
	if (ramFull == true) {
		cfree(key);
		cfree(value);
		writeInt(&DB_FULL, out);
		return;
	}

	// 结果数据包 长度为:SIZE_INT*3+keylen
	// 操作号(int) res(int) keylen(int){不含\0} key(char*){不含\0}
	// 插入失败
	if (res == DB_CMD_ERR) {
		cfree(key);
		cfree(value);
	}

	writeInt(&ADD, out);
	writeInt(&res, out);
	writeInt(&keylen, out);
	writeString(key, out, keylen);
}

void getCmd(ByteArray* in, ByteArray* out) {
	int keylen, valuelen;
	char* key;
	void* value;

	// 获取
	// 数据包格式为:
	// keylen(int){不含\0} key(char*){不含\0}
	readInt(&keylen, in);
	// 长度错误
	if (keylen == 0) {
		writeInt(&DB_ERROR, out);
		return;
	}

	key = (char*) malloc(keylen + 1);
	readString(key, in, keylen);

	value = dbGet(key, keylen);
	valuelen = 0;
	if (value != NULL) {
		valuelen = getSize(value);
	}
	// 结果数据包 长度为:SIZE_INT*3+keylen+valueLen
	// 操作号(int)keylen(int){不含\0} valueLen(int) key(char*){不含\0} value(void*)
	writeInt(&GET, out);
	writeInt(&keylen, out);
	writeInt(&valuelen, out);
	writeString(key, out, keylen);
	if (valuelen != 0)
		writeBuff(value, out, valuelen);

	free(key);
}

void setCmd(ByteArray* in, ByteArray* out) {

	int keylen, valuelen, res;
	char* key;
	void* value;
	// set
	// 数据包格式为:
	// keylen(int){不含\0} valuelen(int) key(char*){不含\0} value(void*)
	readInt(&keylen, in);
	readInt(&valuelen, in);

	// 长度错误
	if (keylen == 0 || valuelen == 0) {
		writeInt(&DB_ERROR, out);
		return;
	}

	key = (char*) cmalloc(keylen + 1);
	value = cmalloc(valuelen);
	readString(key, in, keylen);
	readBuff(value, in, valuelen);
	res = dbSet(key, value, keylen, valuelen);

	// 内存不可再写，拒绝修改型命令
	if (ramFull == true) {
		cfree(key);
		cfree(value);
		writeInt(&DB_FULL, out);
		return;
	}

	// 结果数据包 长度为:SIZE_INT*3+keylen
	// 操作号(int)res(int) keylen(int){不含\0} key(char*){不含\0}

	writeInt(&SET, out);
	writeInt(&res, out);
	writeInt(&keylen, out);
	writeString(key, out, keylen);
}

void replaceCmd(ByteArray* in, ByteArray* out) {

	int keylen, valuelen, res;
	char* key;
	void* value;
	// replace
	// 数据包格式为:
	// keylen(int){不含\0} valuelen(int) key(char*){不含\0} value(void*)
	readInt(&keylen, in);
	readInt(&valuelen, in);

	// 长度错误
	if (keylen == 0 || valuelen == 0) {
		writeInt(&DB_ERROR, out);
		return;
	}

	key = (char*) cmalloc(keylen + 1);
	value = cmalloc(valuelen);
	readString(key, in, keylen);
	readBuff(value, in, valuelen);
	res = dbReplace(key, value, keylen, valuelen);

	// 内存不可再写，拒绝修改型命令
	if (ramFull == true) {
		cfree(key);
		cfree(value);
		writeInt(&DB_FULL, out);
		return;
	}

	// 结果数据包 长度为:SIZE_INT*3+keylen
	// 操作号(int) res(int) keylen(int){不含\0} key(char*){不含\0}
	// 插入失败
	if (res == DB_CMD_ERR) {
		cfree(key);
		cfree(value);
	}

	writeInt(&REPLACE, out);
	writeInt(&res, out);
	writeInt(&keylen, out);
	writeString(key, out, keylen);
}

void removeCmd(ByteArray* in, ByteArray* out) {
	int keylen, res;
	char* key;

	// remove
	// 数据包格式为:
	// keylen(int){不含\0} key(char*){不含\0}
	readInt(&keylen, in);
	// 长度错误
	if (keylen == 0) {
		writeInt(&DB_ERROR, out);
		return;
	}

	key = (char*) malloc(keylen + 1);
	readString(key, in, keylen);

	res = dbRemove(key, keylen);
	// 结果数据包 长度为:SIZE_INT*3+keylen
	// 操作号(int) res(int) keylen(int){不含\0} key(char*){不含\0}
	writeInt(&REMOVE, out);
	writeInt(&res, out);
	writeInt(&keylen, out);
	writeString(key, out, keylen);

	free(key);
}

void addIndexCmd(ByteArray* in, ByteArray* out) {
	int keylen, indexlen, res;
	char* key, *index;

	// 添加索引
	// 数据包格式为:
	// indexlen(int){不含\0} keylen(int){不含\0} index(char*){不含\0} key(char*){不含\0}
	readInt(&indexlen, in);
	readInt(&keylen, in);

	if (keylen == 0 || indexlen == 0) {
		writeInt(&DB_ERROR, out);
		return;
	}

	index = (char*) cmalloc(indexlen + 1);
	key = (char*) cmalloc(keylen + 1);

	readString(index, in, indexlen);
	readString(key, in, keylen);

	// 内存不可再写，拒绝修改型命令
	if (ramFull == true) {
		cfree(key);
		cfree (index);
		writeInt(&DB_FULL, out);
		return;
	}
	res = dbAdd(index, key, indexlen, keylen + 1);

	// 结果数据包 长度为:SIZE_INT*3+keylen
	// 操作号(int) res(int) keylen(int){不含\0} key(char*){不含\0}
	// 插入失败
	if (res == DB_CMD_ERR) {
		cfree(index);
		cfree(key);
	}

	writeInt(&ADD_INDEX, out);
	writeInt(&res, out);
	writeInt(&indexlen, out);
	writeString(index, out, indexlen);
}

void delIndexCmd(ByteArray* in, ByteArray* out) {
	int indexlen, res;
	char* index;

	// 删除索引
	// 数据包格式为:
	// indexlen(int){不含\0} index(char*){不含\0}
	readInt(&indexlen, in);

	if (indexlen == 0) {
		writeInt(&DB_ERROR, out);
		return;
	}

	index = (char*) cmalloc(indexlen + 1);

	readString(index, in, indexlen);

	res = dbRemove(index, indexlen);

	// 结果数据包 长度为:SIZE_INT*3+keylen
	// 操作号(int) res(int) keylen(int){不含\0} key(char*){不含\0}
	// 删除失败
	if (res == DB_CMD_ERR) {
		cfree(index);
	}

	writeInt(&DEL_INDEX, out);
	writeInt(&res, out);
	writeInt(&indexlen, out);
	writeString(index, out, indexlen);
}

void getByIndexCmd(ByteArray* in, ByteArray* out) {
	int indexlen, keylen, valuelen;
	char* index, *key;
	void* value;

	// 通过index获取
	// 数据包格式为:
	// indexlen(int){不含\0} index(char*){不含\0}
	readInt(&indexlen, in);
	// 长度错误
	if (indexlen == 0) {
		writeInt(&DB_ERROR, out);
		return;
	}

	index = (char*) malloc(indexlen + 1);
	readString(index, in, indexlen);

	key = (char*) dbGet(index, indexlen);

	// index 不存在
	if (key == NULL) {
		writeInt(&DB_ERROR, out);
		return;
	}
	keylen = getSize(key);
	value = dbGet(key, keylen);

	valuelen = 0;
	if (value != NULL) {
		valuelen = getSize(value);
	}
	// 结果数据包 长度为:SIZE_INT*3+keylen+valueLen
	// 操作号(int)keylen(int){不含\0} valueLen(int) key(char*){不含\0} value(void*)
	writeInt(&GET, out);
	writeInt(&keylen, out);
	writeInt(&valuelen, out);
	writeString(key, out, keylen);
	if (valuelen != 0)
		writeBuff(value, out, valuelen);

	free(index);
}
